/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "iot_cloud.h"
#include "iot_profile.h"
#include "cJSON.h"
#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "kv_store.h"
#include "iot_main.h"

int Iot_GetStartTime(void)
{
    return IOT_ScheduleGetStartTime();
}

/**
 * @brief deal the message received from the queue
 *
 */
static int IotProfile_SetHumidityThreshold(cJSON *objCmd)
{
    int ret = -1;
    cJSON *objParas = NULL;
    cJSON *objParaHumidityHig= NULL;

    if ((objParas = cJSON_GetObjectItem(objCmd, "paras")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "Could not get paras in json");
        return ret;
    }
    
    objParaHumidityHig = cJSON_GetObjectItem(objParas, "HumidityHig");
    
    if (objParaHumidityHig != NULL) {      
        int  humidityHig = cJSON_GetNumberValue(objParaHumidityHig);

        if (humidityHig >= 40  && humidityHig <= 90 ) {

            IotMain_SetHuidityThreshold(humidityHig);
            RaiseLog(LOG_LEVEL_ERR, "humidityThreshold=%d",humidityHig);
            ret = 1;
        }

    } else {
        RaiseLog(LOG_LEVEL_ERR, "Para not exist");
    }
    return ret;
}


int IotMain_UpdateShedule(CommandParamSetShedule *shedule)
{
    if (shedule->num == 1 && shedule->day[0] == 0) {        // set the one time schedule to current weekday
        shedule->day[0] = (IotMain_GetCurDay() + 1);
    }

    switch (shedule->option) {
        case 'A':
            IOT_ScheduleAdd(shedule->scheduleID, shedule->day, shedule->num, shedule->startHour * CN_SECONDS_IN_HOUR +\
                shedule->startMinute * CN_SECONDS_IN_MINUTE, shedule->duration * CN_SECONDS_IN_MINUTE, shedule->switchStatus.status, 0);
            break;
        case 'U':
            IOT_ScheduleUpdate(shedule->scheduleID, shedule->day, shedule->num, shedule->startHour * CN_SECONDS_IN_HOUR +\
                shedule->startMinute * CN_SECONDS_IN_MINUTE, shedule->duration * CN_SECONDS_IN_MINUTE, shedule->switchStatus.status, 0);
            break;
        case 'D':
            IOT_ScheduleDelete(shedule->scheduleID, shedule->day, shedule->num, shedule->startHour * CN_SECONDS_IN_HOUR +\
                shedule->startMinute * CN_SECONDS_IN_MINUTE, shedule->duration * CN_SECONDS_IN_MINUTE, shedule->switchStatus.status, 0);
            break;
        default:
            RaiseLog(LOG_LEVEL_ERR, "the schedule has no such option!\n");
            break;
    }

    return 0;
}

/**
 * @brief Callback function used to process commands delivered by the Cloud Platform
 * @param command Indicates the command delivered by the Cloud Platform
 * @param value Indicates the parameter corresponding to the command
 * @return Returns 0 success while -1 failed
 */
int IotProfile_CommandCallback(int command, void *buf)
{
    CommandParamSetShedule setSheduleParam;
    CLOUD_CommandType cmd = (CLOUD_CommandType)command;

    /**
     * Here, we only process the command for controlling the motor issued by the Cloud Platform, and the
     * value should be CN_BOARD_SWITCH_ON or CN_BOARD_SWITCH_OFF
     */

    if (cmd == CLOUD_COMMAND_SETSHEDULE) {
        setSheduleParam = *(CommandParamSetShedule *)buf;
        RaiseLog(LOG_LEVEL_INFO, "setshedule:day:%d hour:%d minute:%d duration:%d\r\n", \
                setSheduleParam.day,setSheduleParam.startHour, setSheduleParam.startMinute, setSheduleParam.duration);
        return IotMain_UpdateShedule(&setSheduleParam);
    }

    return -1;
}

/**
 * @brief we make the data to a json string and send it to the iot cloud engine
 *
 */
int IotProfile_Report(int HumidifierStatus, int Humidity ,int HumidityHig)
{
    int ret = -1;
    char *jsonString;
    IotProfileService    service;
    IotProfileKV  kvHumidifierStatus;
    IotProfileKV  kvHumidity;
    IotProfileKV  kvHumidityHig;

    /* package the data */
    service.eventTime = NULL;
    service.serviceID = "SmartHumidifier";
    service.propertyLst = &kvHumidifierStatus;
    service.nxt = NULL;

    kvHumidifierStatus.key = "HumidifierStatus";
    kvHumidifierStatus.value = HumidifierStatus ? "ON" : "OFF";
    kvHumidifierStatus.type = IOT_PROFILE_KEY_DATATYPE_STRING;
    kvHumidifierStatus.nxt = &kvHumidity;

    kvHumidity.key = "Humidity";
    kvHumidity.value = &Humidity;
    kvHumidity.type = IOT_PROFILE_KEY_DATATYPE_INT;
    kvHumidity.nxt = &kvHumidityHig;

    kvHumidityHig.key = "HumidityHig";
    kvHumidityHig.value = &HumidityHig;
    kvHumidityHig.type = IOT_PROFILE_KEY_DATATYPE_INT;
    kvHumidityHig.nxt = NULL;

    jsonString = IoTProfilePackage(&service);
    if (NULL != jsonString) {
        RaiseLog(LOG_LEVEL_INFO, "jsonString:%s", jsonString);

        ret = CLOUD_ReportMsg(jsonString);
        free(jsonString);
    } else {
        RaiseLog(LOG_LEVEL_ERR, "format the report message error");
    }
    return ret;
}

/**
 * @brief deal the message received from the queue
 *
 */
static int IotProfile_SetHumidifierStatus(cJSON *objCmd)
{
    int ret = -1;
    cJSON *objParas = NULL;
    cJSON *objParaHumidifierStatus = NULL;

    if ((objParas = cJSON_GetObjectItem(objCmd, "paras")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "Could not get paras in json");
        return ret;
    }
    objParaHumidifierStatus= cJSON_GetObjectItem(objParas, "HumidifierStatus");

    if (objParaHumidifierStatus != NULL) {      

        char *status = cJSON_GetStringValue(objParaHumidifierStatus);

        if(status != NULL){
            if (strncmp(status,"ON",sizeof("ON")) == 0) {
                IotMain_CloudSet(true);
            }else if(strncmp(status,"OFF",sizeof("OFF")) == 0){
                IotMain_CloudSet(false);
            }
        }else{
            RaiseLog(LOG_LEVEL_ERR,"get switchSts error!\n");
            return ret;
        }

        RaiseLog(LOG_LEVEL_ERR,"g_HumidifierSts.switchSts=%d\n", IotMain_GetMotorSts());
        ret = 1;
    } else {
        RaiseLog(LOG_LEVEL_ERR, "Para not exist");
    }
    return ret;
}


static int IotProfile_GetScheduleWeekDays(const char *weekdaystr, int *weekday, int length)
{
    int num = 0;
    char *ps, *pe;

    ps = weekdaystr;
    for (int i = 0; i < length; i++) {
        char day[2] = {0};
        pe = strchr(ps, ',');
        if (pe == NULL) {
            num = i + 1;
            weekday[i] = atoi(ps);
            break;
        }

        day[0] = *ps;
        ps = pe + 1;
        weekday[i] = atoi(day);
    }

    return num;
}

static int IotProfile_GetCommandSetSwitch(CommandParamSetSwitch *setSwitchParam, cJSON *objCmd)
{
    cJSON *objPara = NULL;

    if (setSwitchParam == NULL || objCmd == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "NULL POINT!\n");
        return -1;
    }

    memset(setSwitchParam, 0x00, sizeof(CommandParamSetSwitch));

    if ((objPara = cJSON_GetObjectItem(objCmd, "HumidifierStatus")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "cJSON_GetObjectItem LampStatus failed!\n");
        return -1;
    }
    if (0 == strcmp(cJSON_GetStringValue(objPara), "ON")) {
        setSwitchParam->status = CN_BOARD_SWITCH_ON;
    }
    else {
        setSwitchParam->status = CN_BOARD_SWITCH_OFF;
    }
    RaiseLog(LOG_LEVEL_INFO, "status:%s\n", setSwitchParam->status ? "ON" : "OFF");
    return 0;
}

static int IotProfile_DealSetShedule(cJSON *objCmd)
{
    int ret = -1;
    cJSON *objParaCommand = NULL;
    cJSON *objParas = NULL;
    cJSON *objPara = NULL;
    CommandParamSetShedule setSheduleParam;
    memset(&setSheduleParam, 0x00, sizeof(CommandParamSetShedule));

    if ((objParas = cJSON_GetObjectItem(objCmd, "paras")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "Paras not exist");
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "Day")) != NULL) {
        char *weekdays = cJSON_GetStringValue(objPara);
        setSheduleParam.num = IotProfile_GetScheduleWeekDays(weekdays, setSheduleParam.day, CN_MAX_WEEKDAY);
    } else {
        RaiseLog(LOG_LEVEL_ERR,"exit at Day\n");
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "StartHour")) != NULL) {
        setSheduleParam.startHour = cJSON_GetNumberValue(objPara);
    } else {
        RaiseLog(LOG_LEVEL_ERR,"exit at StartHour\n");
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "StartMinute")) != NULL) {
        setSheduleParam.startMinute = cJSON_GetNumberValue(objPara);
    } else {
        RaiseLog(LOG_LEVEL_ERR,"exit at StartMinute\n");
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "DurationMinutes")) != NULL) {
        setSheduleParam.duration = cJSON_GetNumberValue(objPara);
    } else {
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "ScheduleID")) != NULL) {
        strcpy(setSheduleParam.scheduleID, cJSON_GetStringValue(objPara));
    } else {
        RaiseLog(LOG_LEVEL_ERR,"exit at ScheduleID\n");
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "Option")) != NULL) {
        setSheduleParam.option = *(cJSON_GetStringValue(objPara));
    } else {
         RaiseLog(LOG_LEVEL_ERR,"exit at Option\n");
        return ret;
    }

    if ((objPara = cJSON_GetObjectItem(objParas, "Command")) != NULL) {
        if (IotProfile_GetCommandSetSwitch(&(setSheduleParam.switchStatus), objPara) < 0) {
            return ret;
        }
    } else {
        RaiseLog(LOG_LEVEL_ERR,"exit at Command\n");
        return ret;
    }

    IotMain_AddScheduleDisplay(setSheduleParam);

    ret = IotProfile_CommandCallback(CLOUD_COMMAND_SETSHEDULE, &setSheduleParam);

    return ret;
}


int CLOUD_CommandCallBack(const char *jsonString)
{
    cJSON *objRoot = NULL;
    cJSON *objCmdName = NULL;
    int ret = -1;
    RaiseLog(LOG_LEVEL_ERR,"CLOUD_CommandCallBackcmd entry\n");
    if (jsonString == NULL) {
        RaiseLog(LOG_LEVEL_ERR,"CLOUD_CommandCallBackcmd return ret\n");
        return ret;
    }

    if ((objRoot = cJSON_Parse(jsonString)) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "could not parse the payload\r\n");
        goto EXIT_JSONPARSE;
    }

    if ((objCmdName = cJSON_GetObjectItem(objRoot, "command_name")) == NULL) {
        RaiseLog(LOG_LEVEL_ERR, "%s:could not get the cmd name from json\r\n");
        goto EXIT_CMDOBJ;
    }

    char *retChar = cJSON_GetStringValue(objCmdName);

    RaiseLog(LOG_LEVEL_ERR,"CLOUD_CommandCallBackcmd =%s.\n", retChar);

    if (0 == strcmp(cJSON_GetStringValue(objCmdName), "SetHumidifierStatus")) {
        ret = IotProfile_SetHumidifierStatus(objRoot);
    } else if (0 == strcmp(cJSON_GetStringValue(objCmdName), "SetHumidityThreshold")) {
        ret = IotProfile_SetHumidityThreshold(objRoot);
    } else if (0 == strcmp(cJSON_GetStringValue(objCmdName), "SetSchedule")) {
        ret = IotProfile_DealSetShedule(objRoot);
    } else {
        RaiseLog(LOG_LEVEL_ERR,"unresolved command:%d\r\n", cJSON_GetStringValue(objCmdName));
    }

EXIT_CMDOBJ:
EXIT_JSONPARSE:
    if (objRoot != NULL) {
        cJSON_Delete(objRoot);
    }
    return ret;
}




